<template>
  <div class="llm-chat-msg-box farm-content" v-if="isShowMsg">
    <div v-html="msgNode.msg" :class="msgNode.type" v-for="(msgNode, index) in histHtmlmsg" :key="index"></div>
    <div v-if="curentMsg.html" v-html="curentMsg.html" class="sys"></div>
  </div>
</template>
<script setup lang="ts">
import { marked } from 'marked';
import Farm2Request from '@/service/remoteRequests/Farm2Request';
import { onUnmounted, reactive } from 'vue';
import { RequestTypeEnum } from '@/types/commons/RequestTypeEnum';
import type { DataResponse } from '@/types/commons/DataResponse';
import notice from '@/components/msg/FarmNotice';
import type { TalkMsg } from '@/types/ai/TalkMsg';
import type { SendMsg } from '@/types/ai/SendMsg';
const curentMsg = reactive({ text: '', html: '', talkKey: '' });
const histHtmlmsg = reactive<TalkMsg[]>([]);

const props = defineProps({
  isShowMsg: {
    type: Boolean,
    required: true,
  },
  scrollToBottom: {
    type: Function,
    required: false,
  },
  startHandle: {
    type: Function,
    required: true,
  },
  endHandle: {
    type: Function,
    required: true,
  }
});


let eventSource: EventSource | null = null;
const connectToSSE = (talkKey: string, textHandle?: (text: string, html?: string) => void) => {
  props.startHandle();
  eventSource = new EventSource(Farm2Request.getFullPath('api/wchat/stream') + "?key=" + talkKey);
  eventSource.onmessage = (event: MessageEvent<string>) => {

    const newMessage = event.data;

    curentMsg.text += newMessage.replaceAll('[KG|KG]', ' ').replaceAll('[HH|HH]', '\n');


    curentMsg.text = curentMsg.text.replace('<think>', '<div class="think">').replace('</think>', '</div>').replaceAll(/<div class="think">\s*<\/div>/g, '');

    curentMsg.html = marked.parse(curentMsg.text) as string;
    curentMsg.talkKey = talkKey;
    if (textHandle) {
      textHandle(curentMsg.text, curentMsg.html);
    }
    if (props.scrollToBottom) {
      props.scrollToBottom();
    }
  };

  eventSource.onerror = (error: Event) => {

    if (eventSource) {
      eventSource.close();

      stopTalkEvent();
    }
  };
};
/**
 * 立即停止接收消息
 */
const stopTalkEvent = () => {

  histHtmlmsg.push({ msg: curentMsg.html, type: 'sys', talkKey: curentMsg.talkKey });
  curentMsg.text = '';
  curentMsg.html = '';
  curentMsg.talkKey = '';
  props.endHandle();
}


/**
 * 发送消息给大模型
 * @param sendMsg
 */
const senMsg = (sendMsg: SendMsg, textHandle?: (text: string, html?: string) => void) => {
  histHtmlmsg.push({ msg: sendMsg.msg, type: 'user' });

  sendMsg.hisTalkKeys = histHtmlmsg.map(node => node.talkKey).filter(node => node != null).slice(-5);;

  if (sendMsg && sendMsg.msg.trim()) {
    props.startHandle();
    Farm2Request.submit('api/wchat/creattalk', RequestTypeEnum.post, null, sendMsg).then((response: DataResponse) => {
      connectToSSE((response.data as { key: string }).key, textHandle);
    }).catch((msg: string) => {
      notice.byError(msg);
      stopTalkEvent();
    });
  }
};

/**
 * 清空对话
 */
const clearMsg = () => {
  histHtmlmsg.length = 0;
  curentMsg.text = "";
  curentMsg.html = "";
  props.endHandle();
};

const stopTalk = () => {
  if (eventSource) {
    eventSource.close();
    stopTalkEvent();
  }
};
const getHtmls = () => {
  return histHtmlmsg;
};
const isTalking = () => {
  if (eventSource && eventSource.readyState == 1) {
    return true;
  } else {
    return false;
  }
}



onUnmounted(() => {
  if (eventSource) {
    eventSource.close();
  }
});

defineExpose({ senMsg, clearMsg, stopTalk, getHtmls, isTalking })


</script>
<style>
.think {
  font-size: 12px;
  line-height: 1.2em;
  color: #666666;
  padding: 10px;
  border-left: 5px solid #888;
}
</style>
<style scoped>
/* 样式可以根据需要添加 */
.llm-chat-msg-box.farm-content {
  color: #555555;
  font-size: 14px;
}

.llm-chat-msg-box.farm-content .user {
  background-color: var(--el-color-danger-light-9);
  padding: 10px;
  border-radius: 16px 0px 0px 16px;
  margin-left: 10px;
  margin-bottom: 20px;
}

.llm-chat-msg-box.farm-content .sys {
  background-color: var(--el-color-success-light-9);
  padding: 10px;
  border-radius: 0px 16px 16px 0px;
  margin-right: 10px;
  margin-bottom: 20px;
  word-wrap: break-word;
}
</style>
